﻿using Aspose.Cells;
using Bentley.CifNET.GeometryModel.SDK;
using Bentley.CifNET.SDK;
using Bentley.GeometryNET.Common;
using Bentley.TerrainModelNET;
using CheccCoverplateCulvertAssemble.Common.Total;
using CheccCoverplateCulvertAssemble.Conmmon;
using CheccCoverplateCulvertAssemble.Entity;
using CheccCoverplateCulvertAssemble.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Bentley.CIMNET.CIMGeometry.Solid.SolidUtil.Modify;

namespace CheccCoverplateCulvertAssemble.Operation
{
    /// <summary>
    /// 跌水井
    /// </summary>
    internal class DropWell
    {
        DropWellBase dropWellBase;
        private double overHeight;  //涵顶以上墙高
        private double bottomHeight; //涵底高度
        private double clearSpan; //跨径
        private double culvertAngle; //洞口角度
        public DropWell(DropWellBase dropWellBase, double overHeight,double bottomHeight,double clearSpan,double culvertAngle)
        {
            this.dropWellBase = dropWellBase;
            this.overHeight = overHeight / 100;
            this.bottomHeight = bottomHeight / 100;
            this.clearSpan = clearSpan;
            this.culvertAngle = culvertAngle;
        }
        public Element CreateEntityModel()
        {
            var objParameter = GetUorCoverParameter();
            double leftHeight = objParameter.precisionPavingHeight + objParameter.sandPitDepthSwim + this.bottomHeight + this.overHeight;
            double rightHeight = objParameter.precisionPavingHeight + objParameter.deep + objParameter.depthOfDrainageDitch;
            //立面高度
            double vHeight =  leftHeight > rightHeight ? leftHeight : rightHeight;
            //底宽
            double bottomWidth = this.clearSpan + objParameter.slopOfDrainageDitch * 2;
            //跌井边坡坡度横向长度
            double slopWidth = (vHeight - objParameter.precisionPavingHeight) * objParameter.slope;

            double LeftLateralOffset = Math.Abs((bottomWidth / 2 + slopWidth) * Math.Tan((90 - this.culvertAngle) * Math.PI / 180));
            //洞口长度
            double length = objParameter.centerLength + objParameter.deep * objParameter.wellSlope + objParameter.gutterPavingLength + LeftLateralOffset;
            DPoint3d[] points = 
            {
                new DPoint3d(-LeftLateralOffset, bottomWidth / 2 , 0) * GeneralBank.UorToMeters,
                new DPoint3d(-LeftLateralOffset, bottomWidth / 2 , objParameter.precisionPavingHeight) * GeneralBank.UorToMeters,
                new DPoint3d(-LeftLateralOffset, (bottomWidth / 2 + slopWidth)  , vHeight) * GeneralBank.UorToMeters,
                new DPoint3d(-LeftLateralOffset, -(bottomWidth / 2 + slopWidth)  , vHeight) * GeneralBank.UorToMeters,
                new DPoint3d(-LeftLateralOffset, -bottomWidth / 2 , objParameter.precisionPavingHeight) * GeneralBank.UorToMeters,
                new DPoint3d(-LeftLateralOffset, -bottomWidth / 2 , 0) * GeneralBank.UorToMeters,
                new DPoint3d(-LeftLateralOffset, bottomWidth / 2 , 0) * GeneralBank.UorToMeters,
            };
            ShapeElement shapeElement = new ShapeElement(GeneralBank.ActiveDgnModel, null, points);
            CurveVector secCur = shapeElement.GetCurveVector();
            LineElement lineElement = new LineElement(GeneralBank.ActiveDgnModel, null, new DSegment3d(
                new DPoint3d(-LeftLateralOffset,0,0),
                new DPoint3d(length, 0,0) * GeneralBank.UorToMeters
                ));
            CurveVector linePath = lineElement.GetCurveVector();
            SolidKernelEntity solidKernel = CreateBodyFromSweep(linePath, secCur, GeneralBank.ActiveDgnModel);

            //角度剪切
            LineElement cutLine = null;
            if (this.culvertAngle < 90)
            {
                cutLine = new LineElement(GeneralBank.ActiveDgnModel, null, new DSegment3d(
                    new DPoint3d(-LeftLateralOffset, -(bottomWidth/ 2 + slopWidth), 0) * GeneralBank.UorToMeters,
                    new DPoint3d(LeftLateralOffset, bottomWidth / 2 + slopWidth, 0) * GeneralBank.UorToMeters));
            }
            else if (this.culvertAngle > 90)
            {
                cutLine = new LineElement(GeneralBank.ActiveDgnModel, null, new DSegment3d(
                    new DPoint3d(LeftLateralOffset, -(bottomWidth /2 + slopWidth), 0) * GeneralBank.UorToMeters,
                    new DPoint3d(-LeftLateralOffset, bottomWidth / 2 + slopWidth, 0) * GeneralBank.UorToMeters));
            }
            if (cutLine != null)
            { 
                Bentley.CIMNET.CIMGeometry.Solid.SolidUtil.Modify.CutSolidsWithCurves(out SolidKernelEntity[] angleCutSolids, solidKernel, cutLine.GetCurveVector(), SolidCutMethod.Split, SolidCutDirection.Both, SolidCutMode.Through, 0);
                solidKernel = angleCutSolids[0];
            }

            //纵面剪切
            double vOffsetL = Math.Abs((leftHeight - objParameter.precisionPavingHeight - objParameter.deep) * objParameter.slopInsideDitch);
            double vOffsetR = Math.Abs(objParameter.depthOfDrainageDitch * objParameter.slopInsideDitch);
            double vWidth = objParameter.centerLength + objParameter.deep * objParameter.wellSlope;
            //洞口顶部剪切
            double cutLinePtY = -(bottomWidth / 2 + slopWidth);
            double cutLinePtX = this.culvertAngle < 90 ? LeftLateralOffset : -LeftLateralOffset;
            DPoint3d[] cutLinePts1 =
            {
                new DPoint3d (-cutLinePtX, cutLinePtY, leftHeight +2)* GeneralBank.UorToMeters,
                new DPoint3d (-cutLinePtX, cutLinePtY, leftHeight)* GeneralBank.UorToMeters,
                new DPoint3d (-cutLinePtX + vOffsetL, cutLinePtY, rightHeight -objParameter.depthOfDrainageDitch)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth - vOffsetR, cutLinePtY, rightHeight -objParameter.depthOfDrainageDitch)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth, cutLinePtY, rightHeight)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth + objParameter.gutterPavingLength + 1, cutLinePtY, rightHeight)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth + objParameter.gutterPavingLength + 1, cutLinePtY, rightHeight + 2)* GeneralBank.UorToMeters
            };
            ShapeElement vCutShape1 = new ShapeElement(GeneralBank.ActiveDgnModel,null, cutLinePts1);
            DPoint3d[] cutLinePts2 =
            {
                new DPoint3d (cutLinePtX, -cutLinePtY, leftHeight+2)* GeneralBank.UorToMeters,
                new DPoint3d (cutLinePtX, -cutLinePtY, leftHeight)* GeneralBank.UorToMeters,
                new DPoint3d (cutLinePtX + vOffsetL, -cutLinePtY, rightHeight -objParameter.depthOfDrainageDitch)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth - vOffsetR, -cutLinePtY, rightHeight -objParameter.depthOfDrainageDitch)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth, -cutLinePtY, rightHeight)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth + objParameter.gutterPavingLength + 1, -cutLinePtY, rightHeight)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth + objParameter.gutterPavingLength + 1, -cutLinePtY, rightHeight +2)* GeneralBank.UorToMeters
            };
            ShapeElement vCutShape2 = new ShapeElement(GeneralBank.ActiveDgnModel, null, cutLinePts2);

            var internalSections = new List<CurveVector>
            {
                vCutShape1.GetCurveVector(),
                vCutShape2.GetCurveVector()
            };
            Create.BodyFromLoft(out SolidKernelEntity outerSolid, internalSections.ToArray(), internalSections.Count, internalSections.ToArray(), 0, GeneralHelpers.Default3DModel, false, false);

            SolidKernelEntity[] solidKernels = new SolidKernelEntity[] { outerSolid };
            BodyBooleanSubtract(ref solidKernel, ref solidKernels, 1);

            //洞口尾部剪切
            Angle angle = Angle.FromRadians(Math.Atan(1 / objParameter.wellSlope));
            double vHeight1 = objParameter.height / Math.Sin(angle.Radians); 
            DPoint3d[] cutLinePts3 =
            {
                new DPoint3d (objParameter.centerLength, 0, 0)* GeneralBank.UorToMeters,
                new DPoint3d (objParameter.centerLength, 0, objParameter.precisionPavingHeight - vHeight1)* GeneralBank.UorToMeters,
                new DPoint3d (objParameter.centerLength + (objParameter.deep + vHeight1 - objParameter.height) * objParameter.slopInsideDitch, 0, objParameter.precisionPavingHeight + objParameter.deep - objParameter.height)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth + objParameter.gutterPavingLength , 0, objParameter.precisionPavingHeight + objParameter.deep - objParameter.height)* GeneralBank.UorToMeters,
            };
            LineStringElement vCutLineString2 = new LineStringElement(GeneralBank.ActiveDgnModel, null, cutLinePts3);
            //vCutLineString2.AddToModel();
            Bentley.CIMNET.CIMGeometry.Solid.SolidUtil.Modify.CutSolidsWithCurves(out SolidKernelEntity[] solidKernelsCut2, solidKernel, vCutLineString2.GetCurveVector(), SolidCutMethod.Split, SolidCutDirection.Both, SolidCutMode.Through, 0);
            //洞口尾部剪切(提取尾部实体)
            DPoint3d[] cutLinePts4 =
            {
                new DPoint3d (objParameter.centerLength, 0, 0)* GeneralBank.UorToMeters,
                new DPoint3d (objParameter.centerLength, 0, objParameter.precisionPavingHeight)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth, 0, objParameter.precisionPavingHeight + objParameter.deep)* GeneralBank.UorToMeters,
                new DPoint3d (vWidth + objParameter.gutterPavingLength , 0, objParameter.precisionPavingHeight + objParameter.deep)* GeneralBank.UorToMeters,
            };
            LineStringElement vCutLineString3 = new LineStringElement(GeneralBank.ActiveDgnModel, null, cutLinePts4);
            //vCutLineString3.AddToModel();
            Bentley.CIMNET.CIMGeometry.Solid.SolidUtil.Modify.CutSolidsWithCurves(out SolidKernelEntity[] solidKernelsCut3, solidKernelsCut2[0], vCutLineString3.GetCurveVector(), SolidCutMethod.Split, SolidCutDirection.Both, SolidCutMode.Through, 0);

            //打孔
            DPoint3d[] dkPTs =
            {
                new DPoint3d(0, (this.clearSpan / 2 + slopWidth)  , vHeight) * GeneralBank.UorToMeters,
                new DPoint3d(0, this.clearSpan / 2 , objParameter.precisionPavingHeight) * GeneralBank.UorToMeters,
                new DPoint3d(0, -this.clearSpan / 2 , objParameter.precisionPavingHeight) * GeneralBank.UorToMeters,
                new DPoint3d(0, -(this.clearSpan / 2 + slopWidth), vHeight) * GeneralBank.UorToMeters,
            };

            LineStringElement vCutLineString4 = new LineStringElement(GeneralBank.ActiveDgnModel, null, dkPTs);
            Bentley.CIMNET.CIMGeometry.Solid.SolidUtil.Modify.CutSolidsWithCurves(out SolidKernelEntity[] bodySolid, solidKernelsCut3[0], vCutLineString4.GetCurveVector(), SolidCutMethod.Split, SolidCutDirection.Both, SolidCutMode.Through, 0);

            //实体合并
            List<SolidKernelEntity> solidKernelEntities = new List<SolidKernelEntity>();
            solidKernelEntities.Add(solidKernelsCut3[1]);
            SolidKernelEntity[] tools = solidKernelEntities.ToArray();
            SolidKernelEntity target = bodySolid[0];
            Bentley.CIMNET.CIMGeometry.Solid.SolidUtil.Modify.BodyBooleanUnion(ref target, ref tools,1);
            Convert1.BodyToElement(out Element resultSolid, target, null, GeneralBank.ActiveDgnModel);

            //位移
            DPoint3d movePt = new DPoint3d(0, 0, -objParameter.precisionPavingHeight) * GeneralBank.UorToMeters; ;
            DTransform3d trans = new DTransform3d(DMatrix3d.Identity);
            trans.Translation = movePt;
            resultSolid.ApplyTransform(new TransformInfo(trans));
            return resultSolid; 
            //resultSolid.AddToModel();
        }


        public SolidKernelEntity CreateBodyFromSweep(CurveVector pathCur, CurveVector secCur, DgnModel modelRef)
        {
            pathCur.GetStartEnd(out DPoint3d startPt, out _, out DVector3d startTangent, out _);
            CurveVector secCur1 = secCur.Clone();
            BCIMNETGS.SolidUtil.Create.BodyFromSweep(out SolidKernelEntity entity, secCur1, pathCur, modelRef, false, true, false, null, null, null, null);
            return entity;
        }

        private (double centerLength, double deep,double wellSlope,  double height, double depthOfDrainageDitch, double slopOfDrainageDitch, double slope, double slopInsideDitch,
            double slopOutsideDitch, double gutterPavingLength, double precisionPavingHeight, double inletSlop, double sandPitDepthSwim) GetUorCoverParameter()
        {
            double centerLength         = this.dropWellBase.CenterLength / 100;
            double deep                 = this.dropWellBase.Deep/ 100;
            double wellSlope            = this.dropWellBase.WellSlope;
            double height               = this.dropWellBase.Height/ 100;
            double depthOfDrainageDitch = this.dropWellBase.DepthOfDrainageDitch/ 100;
            double slopOfDrainageDitch  = this.dropWellBase.SlopOfDrainageDitch/100;
            double slope                = this.dropWellBase.Slope; 
            double slopInsideDitch      = this.dropWellBase.SlopInsideDitch;
            double slopOutsideDitch     = this.dropWellBase.SlopOutsideDitch;
            double gutterPavingLength   = this.dropWellBase.GutterPavingLength/ 100;
            double precisionPavingHeight= this.dropWellBase.PrecisionPavingHeight/ 100;
            double inletSlop            = this.dropWellBase.InletSlop;
            double sandPitDepthSwim     = this.dropWellBase.SandPitDepthSwim/ 100;
            return (centerLength, deep, wellSlope, height, depthOfDrainageDitch, slopOfDrainageDitch, slope, slopInsideDitch, slopOutsideDitch, gutterPavingLength, precisionPavingHeight, inletSlop, sandPitDepthSwim);
        }
    }
}
